/******************************************************************************
 *  _____     _____
 *  \  __\    \  __\
 *   \ \_\\    \ \_\\
 *    \  __\SS  \  __\roject
 *     \_\       \_\
 *
 * Mateusz Maciąg, Rafał Urbański
 * Komputerowe Systemy Sterowania
 *****************************************************************************/

#include "SquareWaveform.h"

#include <cmath>
#include <sstream>

#include "Utils.h"

namespace RafMat
{
namespace SimEngine
{

using namespace std;
using namespace SimInterface;

const std::string SquareWaveform::CONF_AMPLITUDE = "amplitude";
const std::string SquareWaveform::CONF_DUTY = "duty";

SquareWaveform::SquareWaveform(SimInterface::ISimulator& sim,
                        double amplitude, double period,
                        double offset, double phase, double duty)
    : WaveformBase(sim, "Square", "square", amplitude/2, period, offset, phase),
      m_duty(duty)
{
}

double SquareWaveform::getNextValue()
{
    double currentTime = getCurrentTime();
    double ratio = currentTime / getPeriod();

    ratio += getPhase();
    ratio -= floor(ratio);

    if(ratio < m_duty)
        return getOffset() - getGain();
    else
        return getOffset() + getGain();
}

bool SquareWaveform::setParameter(const string& param, const string& value) throw(logic_error)
{
    // Usuń ewentualne wiodące i końcowe spacje
    string tparam = Utils::trimWhiteSpaces(param);
    string tvalue = Utils::trimWhiteSpaces(value);

    // Strumień danych dla łańcucha argumentu.
    istringstream istr(tvalue);

    double tmpVal;

    if(tparam == CONF_AMPLITUDE)
    {
        istr >> tmpVal;
        if(!istr.bad())
        {
            setGain(tmpVal / 2.0);
        }
    }
    else if(tparam == CONF_DUTY)
    {
        istr >> tmpVal;
        if(!istr.bad())
        {
            m_duty = tmpVal;
        }
    }
    else
        return WaveformBase::setParameter(param, value);

    if(istr.bad())
    {
        throw iconf_error::syntaxError(*this, tvalue);
    }

    return true;
}

string SquareWaveform::getParameter(const string& param) const throw(logic_error)
{
    // Usuń ewentualne wiodące i końcowe spacje
    string tparam = Utils::trimWhiteSpaces(param);
    string outStr;

    // Strumień danych dla łańcucha argumentu.
    ostringstream ostr(outStr);

    if(tparam == CONF_AMPLITUDE)
        ostr << getGain() * 2.0;
    else if(tparam == CONF_DUTY)
        ostr << m_duty;
    else
        return WaveformBase::getParameter(param);

    return ostr.str();
}

SimFile::ConfigWriter& SquareWaveform::dumpSpecificPar(SimFile::ConfigWriter& o) const
{
    o.pushParam(CONF_DUTY, m_duty);
    // Wywołaj bazową, bo potrzebne są też pozostałe parametry.
    return WaveformBase::dumpSpecificPar(o);
}

}   // SimEngine namespace
}   // RafMat namespace

